除了Rails本身提供的基本驗證之外,有時候我們會需要客製化驗證,這時候我們可以在 Modle中定義方法來使用,使用方式如下:
自訂驗證方法
class User < ApplicationRecord
  validate :name_validator
  
  private
  def name_validator
    unless name.starts_with? 'Ruby'
        errors[:name] << 'must begin with Ruby'
    end
  end
end
只要errors的hash有東西,存檔(驗證)就不會成功。
在你的驗證方法之中,你會使用到 errors 來將錯誤訊息放進去,如果這個錯誤是因為某一屬性造成,我們就用那個屬性當做 errors 的 key,例如本例的 :name。如果原因不特別屬於某一個屬性,照慣例會用 :base。
但是當你有很多個Model都需要做同樣的驗證時,直接定義在某個Model之下就不會是個很好的做法;
這時,你可以使用下面的Custom Validators,另外建立一個驗證類別,讓多個Model可以使用。
Custom Validators 自訂資料驗證器
只要符合ActiveModel::Validations::ClassMethods 驗證的規定,你可以另外自訂一個驗證類別,並且使用include和validates_with把它呼叫進要驗證的Model,或是直接用validate_each來實現:
簡單的規範如下:
驗證類別必需繼承自ActiveModel::Validator,
類別名稱要是自定義名稱Validator
類別內必須要有一個validate或是validate_each的function並且接受對應參數
使用validate_each:
當遇到email:trueRails會尋找EmailValidator的類別並且使用 validate_each 方法來做驗證。
class EmailValidator < ActiveModel::EachValidator
  def validate_each(record, attr_name, value)
    unless value =~ /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
      record.errors.add :email, "This is some complex validation"
    end
  end
end
class User
  validates :email email: true
end
如果使用的是validate而非validate_each就必須先include並且用validates_with來驗證。
class User
  include ActiveModel::Validations
  validates_with EmailValidator
end
class EmailValidator < ActiveModel::Validator
  def validate(record)
     # Logic to check email is valid or not
     record.errors.add :email, "This is some complex validation"
  end
end
回呼 CallBack
資料驗證及回呼
回呼可以在Model資料的生命週期,掛載事件上去,例如我們可以在資料儲存進資料庫前,做一些修正,或是再儲存成功之後,做一些其他動作。
當一個物件儲存時的流程如下:其中有before/after的地方就是回呼的觸發時機。
save > valid > 
before_validation > 
validate > 
after_validate > 
before_save >
before_create > 
create > 
after_create > 
after_save > 
after_commit
例如:before_validation常用來清理資料或設定預設值:
class Event < ApplicationRecord
  before_validation :setup_defaults
  protected
  def setup_defaults
    self.name.try(:strip!) # 把前後空白去除
  	 self.description = self.name if self.description.blank?
    self.is_public ||= true
  end
end
參考資料:
Rails實戰聖經:資料驗證及回呼
Building Custom Validators in Rails